#include "AppRouter.h"
#include "PageMgr.h"

AppRouter::AppRouter() 
{
	Init();
	SetSwitchAnim();
}
AppRouter::~AppRouter() {
	ClearStack(false);
}

void AppRouter::Init() {
	m_pagePrev = nullptr;
	m_pageCur = nullptr;
	memset(&m_env, 0, sizeof(m_env));
}
void AppRouter::AppInit(){
	
	/* 确认默认组存在 */
	if (!lv_group_get_default())
	{
		lv_group_t* group = lv_group_create();
		lv_group_set_default(group);
	}

	/* 设置屏幕样式*/
	lv_obj_t* screen = lv_scr_act();
	lv_disp_t* display = lv_disp_get_default();

	/* 设置显示器样式 */

	// 设置默认主题
 	lv_theme_t* theme = lv_theme_basic_init(display);
 	lv_disp_set_theme(display, theme);
	
	// 设置显示器背景 
	lv_disp_set_bg_color(display, lv_color_black());
	lv_disp_set_bg_opa(display, LV_OPA_COVER);

	/* 设置屏幕样式 */
	lv_obj_remove_style_all(screen);
	lv_obj_set_style_bg_opa(screen, LV_OPA_COVER, 0); // 不透明
	lv_obj_set_style_bg_color(screen, lv_color_black(), 0); // 纯黑背景色
	lv_obj_clear_flag(screen, LV_OBJ_FLAG_SCROLLABLE); // 无滚动条

	/* 设置body默认样式 */
	lv_style_init(&m_body_style);
	lv_style_set_width(&m_body_style, DISP_HOR_RES);
	lv_style_set_height(&m_body_style, DISP_VER_RES);
	lv_style_set_bg_opa(&m_body_style, LV_OPA_COVER);
	lv_style_set_bg_color(&m_body_style, lv_color_black());

}

bool AppRouter::FourceUnload(IPage* page)
{
	if (page == nullptr)
	{
		LV_LOG_ERROR("Page is nullptr, Unload failed");
		return false;
	}

	LV_LOG_INFO("Page(%s) Fource unloading...", page->m_name);

	if (page->m_state == page_state_em::ACTIVITY)
	{
		LV_LOG_INFO("Page state is ACTIVITY, Disappearing...");
		page->OnViewEnd();
	}

	page->m_state = ExecUnloadState(page);

	return true;
}
void AppRouter::ClearStack(bool keepBottom)
{
	while (true)
	{
		IPage* top = PageMgr::GetStackTop();

		if (top == nullptr)
		{
			LV_LOG_INFO("Page stack is empty, breaking...");
			break;
		}

		IPage* topAfter = PageMgr::GetStackSecond();
		if (topAfter == nullptr)
		{
			if (keepBottom)
			{
				m_pagePrev = top;
				LV_LOG_INFO("Keep page stack bottom(%s), breaking...", top->m_name);
				break;
			}
			else
			{
				m_pagePrev = nullptr;
			}
		}

		FourceUnload(top);

		PageMgr::StackPop();
	}
	LV_LOG_INFO("Stack clear done");
}

bool AppRouter::GetLoadAnimAttr(anim_type_em type, page_anim_attr_t* attr)
{
	lv_coord_t hor = LV_HOR_RES;
	lv_coord_t ver = LV_VER_RES;

	switch (type)
	{
		case anim_type_em::LOAD_ANIM_OVER_LEFT: {
			attr->dragDir = page_drag_dir_t::PAGE_DRAG_DIR_HOR;

			attr->push.entry.start = hor;
			attr->push.entry.end = 0;
			attr->push.exit.start = 0;
			attr->push.exit.end = 0;

			attr->pop.entry.start = 0;
			attr->pop.entry.end = 0;
			attr->pop.exit.start = 0;
			attr->pop.exit.end = hor;
			break;
		}
		case anim_type_em::LOAD_ANIM_OVER_RIGHT: {
			attr->dragDir = page_drag_dir_t::PAGE_DRAG_DIR_HOR;

			attr->push.entry.start = -hor;
			attr->push.entry.end = 0;
			attr->push.exit.start = 0;
			attr->push.exit.end = 0;

			attr->pop.entry.start = 0;
			attr->pop.entry.end = 0;
			attr->pop.exit.start = 0;
			attr->pop.exit.end = -hor;
			break;
		}
		case anim_type_em::LOAD_ANIM_OVER_TOP: {
			attr->dragDir = page_drag_dir_t::PAGE_DRAG_DIR_VER;

			attr->push.entry.start = ver;
			attr->push.entry.end = 0;
			attr->push.exit.start = 0;
			attr->push.exit.end = 0;

			attr->pop.entry.start = 0;
			attr->pop.entry.end = 0;
			attr->pop.exit.start = 0;
			attr->pop.exit.end = ver;
			break;
		}
		case anim_type_em::LOAD_ANIM_OVER_BOTTOM: {
			attr->dragDir = page_drag_dir_t::PAGE_DRAG_DIR_VER;

			attr->push.entry.start = -ver;
			attr->push.entry.end = 0;
			attr->push.exit.start = 0;
			attr->push.exit.end = 0;

			attr->pop.entry.start = 0;
			attr->pop.entry.end = 0;
			attr->pop.exit.start = 0;
			attr->pop.exit.end = -ver;
			break;
		}
		case anim_type_em::LOAD_ANIM_MOVE_LEFT: {
			attr->dragDir = page_drag_dir_t::PAGE_DRAG_DIR_HOR;

			attr->push.entry.start = hor;
			attr->push.entry.end = 0;
			attr->push.exit.start = 0;
			attr->push.exit.end = -hor;

			attr->pop.entry.start = -hor;
			attr->pop.entry.end = 0;
			attr->pop.exit.start = 0;
			attr->pop.exit.end = hor;
			break;
		}
		case anim_type_em::LOAD_ANIM_MOVE_RIGHT: {
			attr->dragDir = page_drag_dir_t::PAGE_DRAG_DIR_HOR;

			attr->push.entry.start = -hor;
			attr->push.entry.end = 0;
			attr->push.exit.start = 0;
			attr->push.exit.end = hor;

			attr->pop.entry.start = hor;
			attr->pop.entry.end = 0;
			attr->pop.exit.start = 0;
			attr->pop.exit.end = -hor;
			break;
		}
		case anim_type_em::LOAD_ANIM_MOVE_TOP: {
			attr->dragDir = page_drag_dir_t::PAGE_DRAG_DIR_VER;

			attr->push.entry.start = ver;
			attr->push.entry.end = 0;
			attr->push.exit.start = 0;
			attr->push.exit.end = -ver;

			attr->pop.entry.start = -ver;
			attr->pop.entry.end = 0;
			attr->pop.exit.start = 0;
			attr->pop.exit.end = ver;
			break;
		}
		case anim_type_em::LOAD_ANIM_MOVE_BOTTOM: {
			attr->dragDir = page_drag_dir_t::PAGE_DRAG_DIR_VER;

			attr->push.entry.start = -ver;
			attr->push.entry.end = 0;
			attr->push.exit.start = 0;
			attr->push.exit.end = ver;

			attr->pop.entry.start = ver;
			attr->pop.entry.end = 0;
			attr->pop.exit.start = 0;
			attr->pop.exit.end = -ver;
			break;
		}
		case anim_type_em::LOAD_ANIM_FADE_ON: {
			attr->dragDir = page_drag_dir_t::PAGE_DRAG_DIR_NONE;

			attr->push.entry.start = LV_OPA_TRANSP;
			attr->push.entry.end = LV_OPA_COVER;
			attr->push.exit.start = LV_OPA_COVER;
			attr->push.exit.end = LV_OPA_COVER;

			attr->pop.entry.start = LV_OPA_COVER;
			attr->pop.entry.end = LV_OPA_COVER;
			attr->pop.exit.start = LV_OPA_COVER;
			attr->pop.exit.end = LV_OPA_TRANSP;
			break;
		}
		case anim_type_em::LOAD_ANIM_NONE: {
			memset(attr, 0, sizeof(page_anim_attr_t));
			return true;
		}
		default: {
			LV_LOG_ERROR("Load anim type error: %d", type);
			return false;
		}
	}

	/* 定义getter和setter函数 */ 

	if (attr->dragDir == page_drag_dir_t::PAGE_DRAG_DIR_HOR)
	{
		// x轴
		attr->setter = [](void* obj, int32_t v){ lv_obj_set_x((lv_obj_t*)obj, v); };
		attr->getter = [](void* obj){ return (int32_t)lv_obj_get_x((lv_obj_t*)obj); };
	}
	else if (attr->dragDir == page_drag_dir_t::PAGE_DRAG_DIR_VER)
	{
		// y轴
		attr->setter = [](void* obj, int32_t v){ lv_obj_set_y((lv_obj_t*)obj, v); };
		attr->getter = [](void* obj){ return (int32_t)lv_obj_get_y((lv_obj_t*)obj); };
	}
	else
	{
		// 背景透明度
		attr->setter = [](void* obj, int32_t v){ lv_obj_set_style_bg_opa((lv_obj_t*)obj, (lv_opa_t)v, LV_PART_MAIN); };
		attr->getter = [](void* obj){ return (int32_t)lv_obj_get_style_bg_opa((lv_obj_t*)obj, LV_PART_MAIN); };
	}

	return true;
}
void AppRouter::AnimInit(lv_anim_t* a)
{
	lv_anim_init(a);

	uint32_t time = (m_pageCur->m_anim.attr.type == anim_type_em::LOAD_ANIM_NONE) ? 0 : m_env.anim_current.time;
	lv_anim_set_time(a, time);
	lv_anim_set_path_cb(a, m_env.anim_current.path);
}

page_state_em AppRouter::ExecLoadState(IPage* page)
{
	LV_LOG_INFO("Page(%s) state load", page->m_name);

	if (page->m_body != nullptr)
		LV_LOG_ERROR("Page(%s) root must be nullptr", page->m_name);

	// 创建屏幕根节点
	lv_obj_t* root = lv_obj_create(lv_scr_act());
	lv_obj_remove_style_all(root);
	lv_obj_clear_flag(root, LV_OBJ_FLAG_SCROLLABLE); // 禁止滚动
	lv_obj_set_user_data(root, page); // 设置根节点对应的页面，便于处理lvgl回调

	// 订阅屏幕滑动事件
	page->AddScreenEvent();

	// 设置默认样式
	lv_obj_add_style(root, &m_body_style, LV_PART_MAIN);

	page->m_body = root;

	// 页面加载响应
	page->OnViewLoad();

	page->m_bCached = page->m_bReqCache;

	// 返回下一个状态
	return page_state_em::WILL_SHOW;
}
page_state_em AppRouter::ExecWillShowState(IPage* page)
{
	LV_LOG_INFO("Page(%s) state will appear", page->m_name);
	
	// 设置不隐藏
	lv_obj_clear_flag(page->m_body, LV_OBJ_FLAG_HIDDEN); 
	
	// 执行转场动画
	SwitchAnimStart(page);
	
	return page_state_em::SHOW;
}
page_state_em AppRouter::ExecShowState(IPage* page)
{
	LV_LOG_INFO("Page(%s) state did appear", page->m_name);

	// 显示完成响应
	page->OnViewShow();

	return page_state_em::ACTIVITY;
}
page_state_em AppRouter::ExecFinaleState(IPage* page)
{
	LV_LOG_INFO("Page(%s) state will disappear", page->m_name);
	
	// 清理屏幕事件
	page->ClearScreenEvent();

	// 页面消失响应 
	page->OnViewEnd();

	// 执行动画
	SwitchAnimStart(page);

	return page_state_em::CLOSE;
}
page_state_em AppRouter::ExecCloseState(IPage* page)
{
	LV_LOG_INFO("Page(%s) state did disappear", page->m_name);
	
	// 设置隐藏
	lv_obj_add_flag(page->m_body, LV_OBJ_FLAG_HIDDEN);

	// 清理定时器
	if (page->m_timer) {
		lv_timer_del(page->m_timer);
		page->m_timer = nullptr;
	}

	if (page->m_bCached)
	{
		LV_LOG_INFO("Page(%s) has cached", page->m_name);
		return page_state_em::WILL_SHOW;
	}
	else
		return page_state_em::UNLOAD;
}
page_state_em AppRouter::ExecUnloadState(IPage* page)
{
	LV_LOG_INFO("Page(%s) state unload", page->m_name);
	if (page->m_body == nullptr)
	{
		LV_LOG_WARN("Page is loaded!");
	}
	else
	{
		// 释放保存的页面数据
		if (page->m_data.buf != nullptr && page->m_data.size != 0)
		{
			LV_LOG_INFO("Page(%s) free stash(0x%p)[%d]", page->m_name, page->m_data.buf, page->m_data.size);
			lv_mem_free(page->m_data.buf);
			page->m_data.buf = nullptr;
			page->m_data.size = 0;
		}

		// 清空屏幕（删除根节点），重置数据
		lv_obj_del_async(page->m_body);
		page->m_body = nullptr;
		page->m_bCached = false;

		// 卸载完成响应
		page->OnViewUnload();
	}

	return page_state_em::IDLE;
}

void AppRouter::StateUpdate(IPage* page)
{
	if (page == nullptr)
		return;

	switch (page->m_state)
	{
		case page_state_em::IDLE: {
			LV_LOG_INFO("Page(%s) state idle", page->m_name);
			break;
		}
		case page_state_em::LOAD: {
			page->m_state = ExecLoadState(page);
			StateUpdate(page);
			break;
		}
		case page_state_em::WILL_SHOW: {
			page->m_state = ExecWillShowState(page);
			break;
		}
		case page_state_em::SHOW: {
			page->m_state = ExecShowState(page);
			LV_LOG_INFO("Page(%s) state active", page->m_name);
			break;
		}
		case page_state_em::ACTIVITY: {
			LV_LOG_INFO("Page(%s) state active break", page->m_name);
			page->m_state = page_state_em::WILL_CLOSE;
			StateUpdate(page);
			break;
		}
		case page_state_em::WILL_CLOSE: {
			page->m_state = ExecFinaleState(page);
			break;
		}
		case page_state_em::CLOSE: {
			page->m_state = ExecCloseState(page);
			if (page->m_state == page_state_em::UNLOAD)
				StateUpdate(page);
			break;
		}
		case page_state_em::UNLOAD: {
			page->m_state = ExecUnloadState(page);
			break;
		}
		default: {
			LV_LOG_ERROR("Page(%s) state[%d] was NOT FOUND!", page->m_name, page->m_state);
			break;
		}
	}
}

void AppRouter::SetSwitchAnim(anim_type_em type, uint16_t time, lv_anim_path_cb_t path)
{
	if (type > anim_type_em::LOAD_ANIM_LAST)
		type = anim_type_em::LOAD_ANIM_NONE;

	m_env.anim_global.type = type;
	m_env.anim_global.time = time;
	m_env.anim_global.path = path;

	LV_LOG_INFO("Set global load anim type = %d", type);
}

void AppRouter::SwitchAnimTypeUpdate(IPage* page) {

	if (page->m_anim.attr.type == anim_type_em::LOAD_ANIM_DEFAULT)
	{
		LV_LOG_INFO("Page(%s) Anim.Type was not set, use default type = %d", page->m_name, m_env.anim_global.type);

		m_env.anim_current = m_env.anim_global;
	}
	else
	{
		if (page->m_anim.attr.type > anim_type_em::LOAD_ANIM_LAST)
		{
			LV_LOG_ERROR("Page(%s) ERROR custom Anim.Type = %d, use default type = %d",
				page->m_name, page->m_anim.attr.type, m_env.anim_global.type);

			page->m_anim.attr = m_env.anim_global;
		}
		else
			LV_LOG_INFO("Page(%s) custom Anim.Type set = %d", page->m_name, page->m_anim.attr.type);

		m_env.anim_current = page->m_anim.attr;
	}
}

bool AppRouter::InSwitch() {
	
	if (m_env.hasSwitchReq ||  // 有转场请求
		m_env.isBusy)          // 转场中 
	{
		LV_LOG_WARN(
			"Page switch busy[AnimState.IsSwitchReq = %d,""AnimState.IsBusy = %d],""request ignored",
			m_env.hasSwitchReq, m_env.isBusy );

		return true;
	}

	return false;

}

bool AppRouter::GoPage(const char* name, const page_data_t* param, bool bRemove) {
	// 是否处于转场中
	if (InSwitch())
		return false;

	// 检测栈中是否存在
	if (PageMgr::GetStackPage(name) != nullptr) {
		LV_LOG_ERROR("Page(%s) can't pushed again", name);
		return false;
	}

	// 检查池中是否存在
	IPage* page = PageMgr::GetPoolPage(name);
	if (page == nullptr)
	{
		LV_LOG_ERROR("Page(%s) was not install", name);
		return false;
	}

	// 是否需要删除当前
	if (bRemove) {
		IPage* top = PageMgr::GetStackTop(); // 取出栈顶页
		if (top)
		{
			top->m_bCached = false; // 移除缓存

			// 删除当前页
			PageMgr::StackPop();

			LV_LOG_INFO("Page(%s) replace Page(%s) (stash = 0x%p)", name, top->m_name, param);
		}
	}
	else
		LV_LOG_INFO("Page(%s) push >> [Screen] (stash = 0x%p)", name, param);

	// 压入新页
	PageMgr::StackPush(page);	

	// 执行转场
	return SwitchTo(page, true, param);
}
bool AppRouter::GoTo(const char* name, const page_data_t* param) {
	return GoPage(name, param, true);
}
bool AppRouter::GoNext(const char* name, const page_data_t* param) {
	return GoPage(name, param, false);
}
bool AppRouter::GoBack(const char* name, const page_data_t* param) {
	// 是否处于转场中
	if (InSwitch())
		return false;

	IPage* top = PageMgr::GetStackTop(); // 取出栈顶页
	if (top == nullptr)
	{
		LV_LOG_WARN("Page stack is empty, cat't pop");
		return false;
	}
	top->m_bCached = false; // 移除缓存
	LV_LOG_INFO("Page(%s) pop << [Screen]", top->m_name);

	// 删除当前页
	PageMgr::StackPop();

	// 获取下一个页面
	top = PageMgr::GetStackTop();

	return SwitchTo(top, false, nullptr);
}
bool AppRouter::GoHome()
{
	// 是否处于转场中
	if (InSwitch())
		return false;

	ClearStack(true);

	m_pagePrev = nullptr;

	IPage* home = PageMgr::GetStackTop();

	SwitchTo(home, false, nullptr);

	return true;
}

void AppRouter::SavePageParam(IPage* page, const page_data_t* param) {

	void* buffer = nullptr;

	// 存在分配区域
	if (page->m_data.buf) 
	{
		// 区域太小，重新分配
		if (page->m_data.size < param->size) 
		{
			buffer = lv_mem_realloc(page->m_data.buf, param->size);
			if (buffer == nullptr)
				LV_LOG_ERROR("page param realloc failed");
			else
				LV_LOG_ERROR("page param(0x%p) realloc[%d]", buffer, param->size);
		}
		else // 区域够用
		{ 
			buffer = page->m_data.buf;
			LV_LOG_INFO("page param(0x%p) is exist", buffer);
		}
	}
	else // 页面没有分配数据区域
	{ 
		buffer = lv_mem_alloc(param->size);
		if (buffer == nullptr)
			LV_LOG_ERROR("page param malloc failed");
		else
			LV_LOG_ERROR("page param(0x%p) malloc[%d]", buffer, param->size);
	}

	if (buffer != nullptr)
	{
		memcpy(buffer, param->buf, param->size);
		LV_LOG_ERROR("stash memcpy[%d] 0x%p >> 0x%p", param->size, param->buf, buffer);
		page->m_data.buf = buffer;
		page->m_data.size = param->size;
	}
}

bool AppRouter::SwitchReqOver() {
	bool ret = false;
	bool lastPageBusy = m_pagePrev && m_pagePrev->m_anim.isBusy;

	// 都不忙，都已完成
	if (!m_pageCur->m_anim.isBusy && !lastPageBusy)
	{
		LV_LOG_INFO("----Page switch was all finished----");
		m_env.hasSwitchReq = false;
		m_pagePrev = m_pageCur;
		ret = true;
	}
	else
	{
		if (m_pageCur->m_anim.isBusy)
			LV_LOG_WARN("Page PageCurrent(%s) is busy", m_pageCur->m_name);
		else
			LV_LOG_WARN("Page PagePrev(%s) is busy", GetPrevPageName());
	}

	return ret;
}
void AppRouter::OnSwitchAnimFinish(lv_anim_t* anim)
{
	IPage* page = (IPage*)lv_anim_get_user_data(anim);
	AppRouter* router = AppRouter::GetInstance();

	LV_LOG_INFO("Page(%s) Anim finish", page->m_name);

	router->StateUpdate(page);

	// 当前页面动画完成
	page->m_anim.isBusy = false;

	bool isFinished = router->SwitchReqOver();

	if (!router->m_env.isEntering && isFinished)
		router->SwitchAnimTypeUpdate(router->m_pageCur);
}
void AppRouter::SwitchAnimStart(IPage* page) {
	page_anim_attr_t animAttr;
	if (!GetCurrentLoadAnimAttr(&animAttr))
		return;

	lv_anim_t a;
	AnimInit(&a);
	lv_anim_set_user_data(&a, page);
	lv_anim_set_var(&a, page->m_body);
	lv_anim_set_ready_cb(&a, OnSwitchAnimFinish);
	lv_anim_set_exec_cb(&a, animAttr.setter);

	int32_t start = 0;

	if (animAttr.getter)
		start = animAttr.getter(page->m_body);

	if (m_env.isEntering)
	{
		if (page->m_anim.isEnter)
			lv_anim_set_values(&a, animAttr.push.entry.start, animAttr.push.entry.end);
		else // Exit 
			lv_anim_set_values(&a, start, animAttr.push.exit.end);
	}
	else // Pop 
	{
		if (page->m_anim.isEnter)
			lv_anim_set_values(&a, animAttr.pop.entry.start, animAttr.pop.entry.end);
		else // Exit 
			lv_anim_set_values(&a, start, animAttr.pop.exit.end);
	}

	// 开始执行动画
	lv_anim_start(&a);
	
	// 置为忙碌
	page->m_anim.isBusy = true;
}
bool AppRouter::SwitchTo(IPage* page, bool isEnter, const page_data_t* param) {

	if (page == nullptr)
	{
		LV_LOG_ERROR("newNode is nullptr");
		return false;
	}

	// 是否有页面转换请求
	if (m_env.hasSwitchReq)
	{
		LV_LOG_WARN("Page switch busy, reqire(%s) is ignore", page->m_name);
		return false;
	}
	m_env.hasSwitchReq = true;

	// 保存页面参数数据
	if (param != nullptr)
	{
		LV_LOG_INFO("page param is detect, %s >> param(0x%p) >> %s", GetPrevPageName(), param, page->m_name);
		SavePageParam(page, param);
	}

	// 切换为当前页
	m_pageCur = page;
	if (m_pageCur->m_bCached) // 页面有缓存，直接显示，无需加载
	{
		LV_LOG_INFO("Page(%s) has cached, appear driectly", m_pageCur->m_name);
		m_pageCur->m_state = page_state_em::WILL_SHOW;
	}
	else 
		m_pageCur->m_state = page_state_em::LOAD; // 需加载
	
	// 修改旧页面相关状态
	if(m_pagePrev)
		m_pagePrev->m_anim.isEnter = false;

	// 当前页为正在进入页
	m_pageCur->m_anim.isEnter = true;

	// 路由器正在切换进入页
	m_env.isEntering = isEnter;
	if (m_env.isEntering) // 页面需要转场，所以得更新转场动画
		SwitchAnimTypeUpdate(m_pageCur);

	// 更新旧页面的状态机
	StateUpdate(m_pagePrev);

	// 更新当前页的状态机
	StateUpdate(m_pageCur);

	// 页面前置
	//if (m_env.isEntering) // 新页面
	//{
	//	LV_LOG_INFO("Page ENTER is detect, move Page(%s) to foreground", m_pageCur->m_name);
	//	if (m_pagePrev)lv_obj_move_foreground(m_pagePrev->m_body);
	//	lv_obj_move_foreground(m_pageCur->m_body);
	//}
	//else //非进入，返回操作
	//{
	//	LV_LOG_INFO("Page EXIT is detect, move Page(%s) to foreground", GetPrevPageName());
	//	lv_obj_move_foreground(m_pageCur->m_body);
	//	if (m_pagePrev)lv_obj_move_foreground(m_pagePrev->m_body);
	//}

	lv_obj_move_foreground(m_pageCur->m_body);

	return true;

}

AppRouter* AppRouter::GetInstance() {
	static AppRouter* router = nullptr;
	if (!router)
		router = new AppRouter;

	return router;
}